﻿#include <graphics.h>
#include <ege/fps.h>
#include <math.h>
#include <time.h>
#include <Windows.h>
#include <iostream>
#include <string>
#include "aoi_impl.h"

#define myrand(m)                 ((float)random(10000) * m / 10000.0f)
#define Distance(x1, y1, x2, y2) (((x1) - (x2))*((x1) - (x2)) + ((y1) - (y2))*((y1) - (y2)))

aoi_mgr_t* aoi_mgr = NULL;
const int max_node_num = 600;
struct AniObj;
struct Obj {
	engine_id_t id;
	char id_str[4];
	float x, y;
	float vx, vy;
	int r;
	int count;
	int color;
	aoi_node_t* aoi_node;
	bool show_frame;
	AniObj* host;

	void draw();
	void draw_mini();
	void draw_mini(Obj& obj);
	void update();
};

int enter_aoi(void * p_aoi_mgr, engine_id_t a, engine_id_t b)
{
	return 0;
}

int leave_aoi(void * p_aoi_mgr, engine_id_t a, engine_id_t b)
{
	return 0;
}

int deal_aoi_batch_event(void * p_aoi_mgr, engine_id_t a, int enter_size, engine_id_t * enter_fid, int leave_size, engine_id_t * leave_fid)
{
	for (int i = 0; i < enter_size; i++)
	{
		aoi_set_relation(aoi_mgr, a, enter_fid[i], 1);

	}
	for (int i = 0; i < leave_size; i++)
	{
		aoi_set_relation(aoi_mgr, a, leave_fid[i], 0);
	}

	return 0;
}

float distance(float x1, float y1, float x2, float y2) {
	return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
}

class AniObj {
public:
	AniObj() {
		for (int i = 0; i < max_node_num; i++) {
			Obj& o = obj[i];
			o.id = i + 1;
			sprintf(o.id_str, "%d", o.id);
			o.x = (float)random(640);
			o.y = (float)random(480);
			o.r = 10;
			o.count = int(random(30));
			o.vx = obj[i].vy = 0.0f;
			o.color = EGEAGRAY(0xff, HSVtoRGB(360.0, 360.0f, 360.0f));
			o.host = this;
			aoi_add_obj_to_scene(aoi_mgr, o.id, o.x, myrand(128), o.y, 100);
			o.aoi_node = aoi_mgr->get_node_with_engine_id(obj[i].id);
		}
	}

	//更新位置等相关属性
	void updateobj() {
		int i, j;
		clock_t t1 = clock();
		for (i = 0; i < max_node_num; i++) {
			obj[i].update();
		}
		for (i = 0; i < max_node_num; i++) {
			memset(obj[i].aoi_node->aoi_calc_filter, -1, (max_node_num + 1) * sizeof(int));
		}
		delta_max = 0;
		for (i = 0; i < max_node_num; i++) {
			clock_t tt1 = clock();
			aoi_move_obj(aoi_mgr, obj[i].id, obj[i].x, 0, obj[i].y);
			clock_t tt2 = clock();
			float delta1 = double(tt2 - tt1) / CLOCKS_PER_SEC;
			delta_max = max(delta1, delta_max);
		}
		clock_t t2 = clock();
		delta = double(t2 - t1) / CLOCKS_PER_SEC;
	}
	void onClick(const mouse_msg& m) {
		if (checker) {
			checker->color = EGEAGRAY(0xff, HSVtoRGB(360.0, 360.0f, 360.0f));
			checker->show_frame = false;
		}
		int i, j;
		for (i = 0; i < max_node_num; i++) {
			if (distance(float(m.x), float(m.y), obj[i].x, obj[i].y) < obj[i].r)
			{
				obj[i].show_frame = true;
				checker = obj + i;
				checker->color = EGEAGRAY(0xff, HSVtoRGB(360.0, 1.0f, 1.0f));
				return;
			}
		}
	}
	//根据属性值绘画
	void drawobj() {

		clock_t t1 = clock();
		for (int i = 0; i < max_node_num; i++) {
			obj[i].draw();
		}
		clock_t t2 = clock();
		double delta1 = double(t2 - t1) / CLOCKS_PER_SEC;

		xyprintf(0, 20, "aoi: %f", delta);
		xyprintf(0, 40, "aoi max: %f", delta_max);
		xyprintf(0, 60, "draw: %f", delta1);
		line(640, 0, 640, 480);
		line(640, 200, 840, 200);
	}

	~AniObj() {
	}

	Obj obj[max_node_num];
	Obj* checker;
	double delta, delta_max;
};

int get_argv(int index, int argv_size, char** argv, int def)
{
	int argv_index = index + 1;
	if (argv_index >= argv_size)
	{
		return def;
	}
	return atoi(argv[argv_index]);
}

void init_argvs(int argv_size, char** argv)
{
}

int main(int argv_size, char** argv) {
	init_argvs(argv_size, argv);
	setinitmode(INIT_ANIMATION);
	initgraph(840, 480);
	setcaption("AOI Example");
	randomize(); //初始化随机种子
	aoi_mgr = (aoi_mgr_t*)create_aoi_mgr(NULL, enter_aoi, leave_aoi, deal_aoi_batch_event, 3, true);
	aoi_mgr->set_max_node_num(max_node_num);
	AniObj aniobj; //定义对象
	fps f;
	ege_enable_aa(true);

	for (; is_run(); delay_fps(60)) {
		aniobj.updateobj(); //更新位置
		while (mousemsg()) {
			mouse_msg m = getmouse();
			if (m.msg == mouse_msg_down) {
				aniobj.onClick(m);
			}
		}
		cleardevice();
		aniobj.drawobj(); //绘画
	}

	closegraph();
	return 0;
}

void Obj::draw()
{
	setfillcolor(color);
	ege_fillellipse(x - r, y - r, r * 2, r * 2);
	outtextxy(x - r / (id < 10 ? 3 : (id < 100 ? 2 : 1.3)), y - r / 2, id_str);
	if (show_frame)
	{
		setlinestyle(CENTER_LINE);
		line(x - 100, y - 100, x + 100, y - 100);
		line(x - 100, y - 100, x - 100, y + 100);
		line(x - 100, y + 100, x + 100, y + 100);
		line(x + 100, y - 100, x + 100, y + 100);
		setlinestyle(SOLID_LINE);

		draw_mini();
		for (int i = 1; i < max_node_num; i++)
		{
			if (aoi_node->bitmap->exists(i))
			{
				host->obj[i - 1].draw_mini(*this);
			}
		}
	}
}

void Obj::draw_mini()
{
	setfillcolor(color);
	float x_ = 100 + 640;
	float y_ = 100;
	ege_fillellipse(x_, y_, r * 2, r * 2);
	outtextxy(x_ + r / (id < 10 ? 1.5 : (id < 100 ? 2 : 3)), y_ + r / 2, id_str);
}

void Obj::draw_mini(Obj& obj)
{
	setfillcolor(EGEAGRAY(0xff, HSVtoRGB(100.f, 43.0f, 46.f)));
	float x_ = 740 + (x - obj.x) - r;
	float y_ = 100 + (y - obj.y) - r;
	ege_fillellipse(x_, y_, r * 2, r * 2);
	outtextxy(x_ + r / (id < 10 ? 1.5 : (id < 100 ? 2 : 3)), y_ + r / 2, id_str);
}

void Obj::update()
{
	if (--count == 0)
	{
		count = int(myrand(400));
		vy = (myrand(0.3) + 0.3f)*(myrand(10) > 5 ? 1 : -1);
		vx = (myrand(0.3) + 0.3f)*(myrand(10) > 5 ? 1 : -1);
	}

	x += vx;
	y += vy;
	if ((y >= 480 - r && vy > 0) || (y < r && vy < 0)) {
		vy = -vy;
		count = int(myrand(400));
	}
	if ((x < r && vx < 0) || (x >= 640 - r && vx > 0))
	{
		vx = -vx;
		count = int(myrand(400));
	}
}

